/************************************************************************/
/*	Perlin Production Co. Ltd. July 2012				*/
/*	GAS, bi-directional Alpha Sprite image Generator, v.2.1		*/
/************************************************************************/

#include "stdio.h"
#include "fdlib.h"
#include "gas.h"

WrtMix(_fd, _alpha, _image,_invert)
FD		*_fd;
char		_alpha;
char		_image;
unsigned	_invert;
{
	char	seq[2];
	seq[0] = _invert ? ~_alpha : _alpha;
	seq[1] = _invert ? (~_image & _alpha) : _image;

	if (write(_fd->file,seq,2) != 2)
		trouble("failed to write to",_fd->name);
}


#define	INCCOL	0
#define	DECCOL	1

WrtCol(_fd, _alpha, _image, _height, _deccol,_invert)
FD		*_fd;
char		*_alpha;
char		*_image;
unsigned	_height;
unsigned	_deccol;
unsigned	_invert;
{
	unsigned	h;

	if (!_deccol)
	 for (h=0; h < _height; ++h)
		WrtMix(_fd,*_alpha++,*_image++,_invert);
	else
	 for (h=0; h < _height; ++h)
		WrtMix(_fd,*--_alpha,*--_image,_invert);
}



WrtDst(_fd, _depth, _width, _height,_invert)
FD		*_fd;
unsigned	_depth;
unsigned	_width;
unsigned	_height;
unsigned	_invert;
{
	FD		*dst;
	char		*alpha,*image;
	int		d,w,h;
	unsigned	plane;
	unsigned	dirrow;

	dst	= &_fd[FD_DST];
	alpha	= _fd[FD_ABM].buf;
	image	= _fd[FD_IBM].buf;
	plane	= _width * _height;
	dirrow	= 1;

	for (d=0; d < _depth; ++d)
	{
	  if (d & 1)
	  {	/* columns in the plane are right to left */
		alpha	+= plane;
		image	+= plane;

		for (w=0; w < _width; ++w)
		{
			if (++dirrow & 1)
			{	/* column rows are bottom to top */
				WrtCol(dst,alpha,image,_height,DECCOL,_invert);
				alpha -= _height;
				image -= _height;
			}
			else
			{	/* column rows are top to bottom */
			 	alpha -= _height;
			 	image -= _height;
			 	WrtCol(dst,alpha,image,_height,INCCOL,_invert);
			}
		}

		alpha	+= plane;
		image	+= plane;
	 }
	 else
	 {	/* columns in the plane are left to right */
		for (w=0; w < _width; ++w)
		{
			if (++dirrow & 1)
			{	/* column rows are top to bottom */
				alpha += _height;
				image += _height;
				WrtCol(dst,alpha,image,_height,DECCOL,_invert);
			}
			else
			{	/* column rows are bottom to top */
				WrtCol(dst,alpha,image,_height,INCCOL,_invert);
				alpha += _height;
				image += _height;
			}
		}
	 }
	}
}


MixAI(_fd, _size, _invert)
FD		*_fd;
unsigned	_size;
unsigned	_invert;
{
	unsigned	i;
	FD		*dst;
	char		*alpha,*image;

	dst	= &_fd[FD_DST];
	alpha	= _fd[FD_ABM].buf;
	image	= _fd[FD_IBM].buf;
	
	
	printf("Writing interleaved file %s\n", dst->name);
	
	for (i=0; i < _size; ++i)
	{
		WrtMix(dst,*alpha++,*image++,_invert);
	}
}


#define	NUM_IP	6
INTPARM	params[NUM_IP];


int main(argc,argv)
int	argc;
char	**argv;
{
	FD	fd[FD_NUM];
	int	phases;
	int	depth;
	int	invert;
	int	width;
	int	height;
	unsigned sizSrc; /* size of the source image in bytes */
	unsigned sizBuf; /* size of image + extra column for shifted sprite */
	unsigned sizDst; /* size of a SINGLE destination image == sizBuf * 2 */
	int	i, step;
	int	incwdt; /* width increment when phases > 1*/
	char	fill;
	int	nbytes;
	INTPARM	*ip;
	int	mirror;
	int	mixer;
	int	format;
	
	if (argc < NPARAM) banner("missing required parameter(s)");

	width	= ArgInt(argv[PI_WDT], 1, MAXSW, "sprite width");
	height	= ArgInt(argv[PI_HGT], 1, MAXSH, "sprite height");
	
	for (i=0; i<FD_NUM; ++i) InitFD(&fd[i]);

	fd[FD_ABM].name = argv[PS_ABM];
	fd[FD_IBM].name = argv[PS_IBM];
	fd[FD_DST].name = argv[PS_DST];

	ip = params;
	InitParm(ip++, 'p', 1, DEFPHS	, MAXPHS, "image phases");
	InitParm(ip++, 'd', 1, DEFSD	, MAXSD	, "sprite depth");
	InitParm(ip++, 'f', 0, SF_DEF	, SF_MAX, "sprite format");
	InitParm(ip++, 'm', 0, 0	, 1	, "bitmap mirror");
	InitParm(ip++, 'i', 0, DEFINV	, 1	, "bitmap inversion mode");
	InitParm(ip++, 'x', 0, 0	, 1	, "mixer mode");
	
	OptParm(argv, NPARAM, argc, params, NUM_IP); /* Optional parameters */
	
	phases	= params[0].ip_val;
	depth	= params[1].ip_val;
	format	= params[2].ip_val;
	mirror  = params[3].ip_val;
	invert	= params[4].ip_val;
	mixer	= params[5].ip_val;
	
	if (!mixer)
	{
		if (format != SF_DEF)
			trouble(SFTxt(format)," input format is not supported");
	}
	else
	{
		format = SF_ANY;
		printf("MIXER MODE: <%s> input format is enforced.\n",SFTxt(format));
		if (phases - 1) trouble("phase generation is not supported in this mode",0);
	}
		
	incwdt	= (phases > 1) ? 1 : 0;

	if (!strcmp(fd[FD_ABM].name,fd[FD_IBM].name))
		usage("source file names must differ");

	if (  !strcmp(fd[FD_ABM].name,fd[FD_DST].name)
	   || !strcmp(fd[FD_IBM].name,fd[FD_DST].name)
	   ) usage("destination file name must be unique");

	OpenFD(&fd[FD_ABM],FCB_READ);
	OpenFD(&fd[FD_IBM],FCB_READ);

	sizSrc	= depth  * width * height;

	for (i=0; i < FD_DST; ++i)
	 if (fd[i].size < sizSrc) trouble("short file",fd[i].name);

	if (fd[FD_ABM].size != fd[FD_IBM].size)
		trouble("input file sizes differ",0);

	sizBuf = depth * height * (width + incwdt);
	sizDst = sizBuf * 2;

	if (invert)	printf("inverted colors, alpha-transparency mask\n");
	else		printf("normal colors  , image-transparency mask\n");

	printf("format: %d (%s)\n", format, SFTxt(format));
	printf("depth : %d, width : %d, height: %d\n", depth, width, height);
	printf("phases: %d, sizSrc: %d, sizDst: %d\n", phases, sizSrc, sizDst);

	fill = invert ? 0xFF : 0;

	ABufFD(&fd[FD_ABM], sizBuf, fill);
	ABufFD(&fd[FD_IBM], sizBuf, 0x00);

	ReadFD(&fd[FD_ABM], depth, width, height, incwdt);
	ReadFD(&fd[FD_IBM], depth, width, height, incwdt);
	
	CreatFD(&fd[FD_DST],FCB_WRITE);
	
	width += incwdt;
	if (mirror)
	{
		MirBuf(&fd[FD_ABM], depth, width, height);
		MirBuf(&fd[FD_IBM], depth, width, height);
	}		
	
	if (!invert)	InvBuf(&fd[FD_ABM]);
		
	if (mixer) MixAI(fd,sizBuf,invert); 
	else
	{
		if (invert)	InvPln(&fd[FD_ABM], depth, width, height);
	
		step = 8 / phases;
	
		for (i = 0; i < phases; i+= step )
		{
			putchar('.');
			WrtDst(fd, depth, width, height,invert);
			RarBuf(&fd[FD_ABM], 0xFF, step, depth, width, height);
			RarBuf(&fd[FD_IBM], 0x00, step, depth, width, height);
		}
	}

	CloseFD(&fd[FD_DST]);

	nbytes = phases * sizDst;

	DisInp(fd[FD_DST].name,nbytes);

	printf	("%x hex bytes successfully written to %s\n"
		, nbytes, fd[FD_DST].name);
	
	for (i=0; i < FD_DST; ++i)
	{
		free(fd[i].buf);
		CloseFD(&fd[i]);
	}
	return 0;
}
